package com.ruoyi.gpt.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.domain.ChatRequestBo;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.gpt.domain.bo.GptUserBo;
import com.ruoyi.gpt.domain.bo.WxMsgBo;
import com.ruoyi.gpt.domain.vo.GptUserVo;
import com.ruoyi.gpt.domain.vo.WxMsgVo;
import com.ruoyi.gpt.service.IGptUserService;
import com.ruoyi.gpt.service.IWxMsgService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.websocket.WebSocketServer;
import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.springframework.beans.factory.annotation.Autowired;

import javax.websocket.Session;
import java.util.Objects;

/**
 * 描述：OpenAI流式输出Socket接收
 *
 * @author https:www.unfbx.com
 * @date 2023-03-23
 */
@Slf4j
@RequiredArgsConstructor
public class OpenAIWebSocketEventSourceListener extends EventSourceListener {

    private Session session;

    private String content;

    private ChatRequestBo chatRequestBo;

    private final IWxMsgService wxMsgService;
    private final IGptUserService gptUserService;

    public OpenAIWebSocketEventSourceListener(ChatRequestBo chatRequestBo) {
        long userId = chatRequestBo.getUserId();
        this.session = WebSocketServer.getSessionByUserId(userId);
        this.chatRequestBo = chatRequestBo;
        this.wxMsgService = SpringUtils.getBean(IWxMsgService.class);
        this.gptUserService = SpringUtils.getBean(IGptUserService.class);
        this.content = "";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onOpen(EventSource eventSource, Response response) {
        log.info("OpenAI建立sse连接...");
    }

    /**
     * {@inheritDoc}
     */
    @SneakyThrows
    @Override
    public void onEvent(EventSource eventSource, String id, String type, String data) {
        log.info("OpenAI返回数据：{}", data);
        if (data.equals("[DONE]")) {
            log.info("OpenAI返回数据结束了");
            if(Objects.isNull(session)){
                return;
            }
            session.getBasicRemote().sendText("[DONE]");
            log.info("chatRequestBo:{}",this.chatRequestBo);

            WxMsgVo wxMsgVo = this.wxMsgService.queryById(this.chatRequestBo.getMsgId());
            if(ObjectUtil.isNotNull(wxMsgVo)){
                wxMsgVo.setRepContent(this.content);
                wxMsgVo.setInOut("2"); // 设置回复类型 2是双向
                wxMsgVo.setResponseTime(DateUtil.between(chatRequestBo.getCreateTime(), DateUtil.date(), DateUnit.SECOND) +"");
                this.wxMsgService.updateByBo(BeanUtil.toBean(wxMsgVo, WxMsgBo.class));
            }
            return;
        }
        ObjectMapper mapper = new ObjectMapper();
        ChatCompletionResponse completionResponse = mapper.readValue(data, ChatCompletionResponse.class); // 读取Json
        String delta = mapper.writeValueAsString(completionResponse.getChoices().get(0).getDelta());
        JSONObject deltaObj = JSONUtil.parseObj(delta);
        if("assistant".equals(deltaObj.get("role"))){
            //此时开始 机器人回复 清空之前的内容
            this.content = "";
            //开始回复 查询出用户，并将调用次数+1 剩余次数如果不是0则-1
            long userId = this.chatRequestBo.getUserId();
            GptUserVo gptUserVo = this.gptUserService.queryById(userId);
            gptUserVo.setGptTotal(gptUserVo.getGptTotal()+1);
            Integer gptRemaining = gptUserVo.getGptRemaining();
            if(gptRemaining > 0){
                // chatRequestBo.getIsSubtract() 为1直接减去，0 相当于免费，无需减去
                gptUserVo.setGptRemaining(gptRemaining - chatRequestBo.getIsSubtract());
            }
            //更新数据库
            this.gptUserService.updateByBo(BeanUtil.toBean(gptUserVo, GptUserBo.class));
        }else{
            //将delta转换成 json 并取出其中的content内容
            String content = deltaObj.getStr("content");
            if(StrUtil.isNotBlank(content)){
                this.content += content;
            }
        }
        if(ObjectUtil.isNull(session)){
            return;
        }
        session.getBasicRemote().sendText(delta);
    }


    @Override
    public void onClosed(EventSource eventSource) {
        log.info("OpenAI关闭sse连接...");
        this.content = "";
    }


    @SneakyThrows
    @Override
    public void onFailure(EventSource eventSource, Throwable t, Response response) {
        if (Objects.isNull(response)) {
            return;
        }
        ResponseBody body = response.body();
        if (Objects.nonNull(body)) {
            log.error("OpenAI  sse连接异常data：{}，异常：{}", body.string(), t);
            log.info("OpenAI返回数据结束了");
            if(Objects.isNull(session)){
                return;
            }
            session.getBasicRemote().sendText(body.string());
            session.getBasicRemote().sendText("[DONE]");
        } else {
            log.error("OpenAI  sse连接异常data：{}，异常：{}", response, t);
            log.info("OpenAI返回数据结束了");
            if(Objects.isNull(session)){
                return;
            }
            session.getBasicRemote().sendText("服务器异常"+response.toString());
            session.getBasicRemote().sendText("[DONE]");
        }
        eventSource.cancel();
    }
}
